<template>
    <Container type="simple" class="g-width100 g-height100" header-style="height:auto;">
        <div slot="header" v-if="showToolbar || operations" class="g-width100 g-height100">
            <!-- 表格工具 -->
            <ButtonGroup :operations="tableOperations">
                <el-scrollbar wrapStyle="max-height:500px;" slot="buttonColumnShowCode">
                    <el-checkbox-group v-model="toolbarMore.checkedItems">
                        <template v-for="(column,index) in columns">
                            <div style="margin-top: 15px;" :key="index">
                                <el-checkbox  :label="column.prop" class="g-block"
                                              :disabled="toolbarMore.checkedItems.length == 1 && toolbarMore.checkedItems.indexOf(column.prop) >=0"
                                >{{column.label}}</el-checkbox>
                            </div>
                        </template>

                    </el-checkbox-group>
                </el-scrollbar>
            </ButtonGroup>

        </div>
        <div slot="main" class="table-wrapper">
            <el-table
                    border
                      size="mini"
                      :data="tableData"
                      class="g-width100"
                      v-loading="localLoading"
                    :empty-text="localEmptyText"
                    highlight-current-row
                    @current-change="handleCurrentChange"
                    @selection-change="handleSelectionChange"
                    ref="table"
            >
                <template v-for="(column,index) in columns">
                    <!-- 加一个默认全部显示的 toolbarMore.checkedItems.length == 0 条件为避免闪屏-->
                <template v-if="column.formatType == undefined">
                    <el-table-column
                            v-if="(toolbarMore.checkedItems.length == 0 || toolbarMore.checkedItems.indexOf(column.prop) >= 0) && !column.showInDetail"
                            :key="index"
                            :prop="column.prop"
                            :label="column.label"
                            :width="column.width"
                            :formatter="column.formatter ? column.formatter : formatter"
                            :show-overflow-tooltip="!!column.tooltip"
                            :type="column.type"
                    >
                    </el-table-column>
                </template>
                    <template v-else>
                        <el-table-column
                                v-if="(toolbarMore.checkedItems.length == 0 || toolbarMore.checkedItems.indexOf(column.prop) >= 0) && !column.showInDetail"
                                :key="index"
                                :prop="column.prop"
                                :label="column.label"
                                :width="column.width"
                                :formatter="column.formatter ? column.formatter : formatter"
                                :show-overflow-tooltip="!!column.tooltip"
                                :type="column.type"
                                style="padding-top: 0;padding-bottom: 0"
                        >
                            <template v-if="column.formatType == 'image'" v-slot:default="scope">

                                <el-image v-if="$_object_getValue(scope.row,column.prop)" class="image-thumbnail" :src="$_object_getValue(scope.row,column.prop)"
                                           :preview-src-list="[$_object_getValue(scope.row,column.prop)]"
                                >
                                    <i slot="error" class="el-icon-picture-outline"></i>
                                </el-image>
                                <template  v-else  >{{defaultCellValue}}</template>
                            </template>
                            <template v-else-if="column.formatType == 'date' || column.formatType == 'datetime'" v-slot:default="scope">
                                {{formatDatetime(scope,column)}}
                            </template>
                            <template v-else-if="column.formatType == 'link'" v-slot:default="scope">
                                <el-link type="primary" :underline="false" @click.stop="column.link.action(scope.row)" v-if="$_object_getValue(scope.row,column.prop)">{{$_object_getValue(scope.row,column.prop)}}</el-link>
                                <template v-else>{{defaultCellValue}}</template>
                            </template>
                        </el-table-column>
                    </template>
                </template>

            </el-table>
            <pagination
                        v-if="pagination.showPage"
                        :current="pagination.current"
                        :page-size="pagination.size"
                        :total="pagination.total"
                        v-on:sizeChange="pageSizeChange"
                        v-on:currentChange="pageNoChange"
            ></pagination>
            <!-- 查看详情的弹窗 -->
            <FormDetailDialog title="详情" ref="formDetailDialog"
                              :layout-column-num="2"
                              :form-data="currentRow"
                              :form-items="detailFormItems"
            >
            </FormDetailDialog>
        </div>
    </Container>
</template>

<script>

    import Container from './Container'
    import Pagination from './Pagination'
    import ButtonGroup from '../common/ButtonGroup.vue'

    import {isArray} from '../../tools/ArrayTools.js'
    import objectMixin from "../../mixin/ObjectMixin"
    import {getPathVar,putPathVar} from '../../tools/StringTools.js'

    import FormDetailDialog from './FormDetailDialog.vue'
    import {parseDate,formatDate} from 'element-ui/src/utils/date-util'
    export default {
        name: "Table",
        mixins:[objectMixin],
        components:{
            Container,
            FormDetailDialog,
            ButtonGroup,
            Pagination
        },
        props: {
            // 列定义
            /*
            columns 说明
            {
                prop:'',// 属性名
                label:'',// 表头名
                width:'',// 宽度
                showInDetail:false,// 是否在详情中展示，true详情中展示,false列表中展示
            }
             */
            columns: {
                type: Array,
                required: true
            },
            // 表格数据
            // 如果是一个字符串则表示是一个url
            // 如果是一个数据组，则表示是数据本身
            // 如果是一个对象，则表示是分页的数据，分页对象格式固定
            data:{

            },
            // 主键属性
            keyProp:{
                type: String,
                default: 'id'
            },
            // data为url有效
            queryParams:{
                type:Object,
                default: function () {
                    return {}
                }
            },
            // 表格数据加载loading状态
            loading: {
                type: Boolean,
                default: false
            },
            // 事件总线的key，配置form表单提交绑定事件
            formSubmitBusKey: {
                type: String,
                default: null
            },
            // 表格无数据时提示
            emptyText:{
                type: String,
                default: '暂无数据'
            },
            // 可操作项定义
            /*
            {
                action:'' // nav delete 请求方法post get put等
                url:''// 对应action的url
                label: '' //按钮的标签
                disabled: false
                disabledOnMissingSelect: true //如果不选中禁用
            }
            */
            showToolbar: {
                type: Boolean,
                default: true
            },
            showToolbarSearch: {
                type: Boolean,
                default: true
            },
            operations:{
                type: Array,
                default: null
            },
            // 自定义按钮的loading状态，key为按钮的code,值为Boolean类型
            buttonLoading:{
                type: Object,
                default:function () {
                    return {}
                }
            },
            operationMoreButtonType:{
                type: String,
                default: 'primary'
            },
            operationMoreButtonIcon:{
                type: String,
                default: ''
            },
            operationMoreButtonText:{
                type: String,
                default: '更多'
            },
            // 唯一标识一条数据的一个文本或属性，主要用来做确定提示用
            //
            uniqueLabel:{
                type:[String,Function],
                default: null
            },
            // 表格数据多选的默认选中值
            checkedKeys:{
                type: Array,
                default: function () {
                    return []
                }
            },
            // 表格数据选中的url，也可以指定一个默认选中的url，一般情况下两个只能选一种
            checkedKeysUrl:{
                type: String
            }
        },
        computed:{
            detailFormItems() {
                let temp = []
                this.columns.forEach(item=>{
                    temp.push(
                        {
                            field: {
                                name: item.prop
                            },
                            element:{
                                type: item.formatType,
                                label: item.label
                            }
                        }
                    )
                })
                return temp
            },

            toolbarOpertions(){
                let toolbar = [
                    {
                        type: 'default',
                        icon: 'el-icon-search',
                        title: '显示/隐藏搜索',
                        show: this.showToolbarSearch,
                        action: ()=> {this.$emit('toolbarSearchClick')}
                    },
                    {
                        type: 'default',
                        icon: 'el-icon-refresh',
                        title: '刷新当前数据',
                        loading: this.localLoading,
                        action: this.toolbarRefreshClick
                    },
                    {
                        type: 'default',
                        icon: 'el-icon-s-grid',
                        title: '显示/隐藏列',
                        code: 'buttonColumnShowCode',
                        popover:{
                            placement: 'bottom',
                            trigger: 'click'
                        }
                    },
                    {
                        type: 'default',
                        icon: 'el-icon-more-outline',
                        title: '取消选择',
                        disabled: ()=> {
                            return !this.currentRow && (!this.multipleSelection || this.multipleSelection.length == 0)
                        },
                        action: this.clearSelection
                    }
                ]
                return toolbar
            },
            tableOperations(){

                let r = []
                if(this.showToolbar){
                    r = r.concat(r,this.toolbarOpertions)
                }
                if(this.operations){
                    this.operations.forEach(button=>{
                        // 克隆一下，要不然会死循环
                        let tempButton = this.$_object_cloneDeep(button)
                        button.action = ()=> {this.handleOperations(tempButton)}
                        button.disabled = ()=>{return this.isButtonDisabled(tempButton)}
                        button.label = ()=>{return this.operationButtonLabel(tempButton)}
                        button.loading = ()=>{return this.localButtonLoading[tempButton.code]}
                        r.push(button)
                    })
                }
                r.sort()
                return r
            },
        },
        created() {
            this.busInit(true)
        },
        destroyed () {
            this.busInit(false)
        },
        mounted(){
            this.toolbarMoreCheckAll()
            if(this.localData){
                this.init(this.localData,this.queryParams)
            }
            // 加载选中的值

            this.getCheckedData()

        },
        data() {
            return {
                localEmptyText: this.emptyText,
                localData: this.data,
                // 真正的数据表格数据
                tableData:[],
                // 表格数据加载loading状态
                localLoading: this.loading,
                // 分页
                pagination:{
                    showPage: false,//是否显示分页组件
                    current:1,
                    size:10,
                    total: 0
                },
                localButtonLoading: this.buttonLoading,
                localQueryParams:this.queryParams,
                // 当前选中的行
                currentRow: null,
                // 多选选中的行
                multipleSelection: null,
                localCheckedKeys: this.checkedKeys,
                toolbarMore:{
                    isIndeterminate: false,
                    checkAll: false,
                    checkedItems:[]
                },
                defaultCellValue: '-'
            }
        },
        methods:{
            // 初始化数据
            init(data,queryParams){
                if(data == null){
                    this.tableData = []
                    this.pagination.showPage = false
                }
                // 如果是字符串，直接请求
                else if(typeof data == 'string'){
                    if(queryParams){
                        this.localQueryParams = queryParams
                    }
                    this.requestData(data,false,queryParams)
                }
                // 如果是数组 直接渲染
                else if(isArray(data)){
                    this.tableData = data
                    this.pagination.showPage = false
                }
                // 如果是对象 当做分页对象处理
                else if (this.$_object_isObject(data)){
                    this.tableData = data.records
                    this.pagination.total = data.total
                    this.pagination.current = data.current
                    this.pagination.size = data.size
                    this.pagination.showPage = true
                }
            },
            // 事件总线相关
            busInit(isBind){
                if(this.formSubmitBusKey){
                    if(isBind){
                        this.$bus.$on(this.formSubmitBusKey,this.handleFormSubmitBus)
                    }else{
                        this.$bus.$off(this.formSubmitBusKey,this.handleFormSubmitBus)
                    }

                }
            },
            // 多选设置选中
            setChecked(checkedKeys){
                this.$nextTick(() => {
                    this.tableData.forEach(row => {
                        if(checkedKeys.indexOf(row[this.keyProp]) >=0){
                            this.$refs.table.toggleRowSelection(row,true);
                        }
                    });
                })
            },
            // 处理表单请求数据
            handleFormSubmitBus(obj){
                if(obj){
                    if(obj.dataType == 'loading'){
                        this.localLoading = obj.loading
                    }else if(obj.dataType == 'data'){
                        this.init(obj.data)
                    }
                }
            },
            // 每面大小改变重新查询数据
            pageSizeChange (val) {
                this.pagination.size = val
                this.$emit('sizeChange', val)
                this.handlePageChange()
            },
            // 页码改变加载对应页码数据
            pageNoChange (val) {
                this.pagination.current = val
                this.$emit('currentChange', val)
                this.handlePageChange()
            },
            // 改变页码处理
            handlePageChange(){
                // 如果是url处理下一页逻辑
                if(typeof this.data == 'string'){
                    this.requestData(this.data,true,this.localQueryParams)
                }else {
                    if(this.formSubmitBusKey){
                        this.$bus.$emit(this.formSubmitBusKey,{dataType:'page',page:{
                                current: this.pagination.current,
                                size:this.pagination.size
                            }})
                    }
                }
            },
            refreshData(){
                // 如果是url处理下一页逻辑
                if(typeof this.data == 'string'){
                    this.requestData(this.data,false,this.localQueryParams)
                }else {
                    if(this.formSubmitBusKey){
                        this.$bus.$emit(this.formSubmitBusKey,{dataType:'refresh'})
                    }
                }
            },
            // 请求后台数据
            requestData(url,page = false,queryParams = {}){
                if(this.localLoading){
                    this.$message.info('数据加载中请耐心等待')
                    return
                }
                this.localLoading = true
                let pageParam = queryParams
                if(page){
                    pageParam.current = this.pagination.current
                    pageParam.size = this.pagination.size
                }
                this.axios.get(url,{params:pageParam}).then(res => {
                    this.localData = res.data
                    this.init(this.localData)
                }).catch((error) =>{
                    if(error.response){
                        if(error.response.status == 401){
                            return
                        }
                        if(error.response.status != 404){
                            this.$message.error(error.response.data.msg)
                        }
                    }else{

                        this.$message.error('网络错误或服务不可用')
                    }
                    this.localData = []
                    this.init(this.localData)
                }).finally(() => {
                    this.localLoading = false
                })
            },
            formatter(row, column, cellValue){
                if(typeof cellValue == 'boolean'){
                    return cellValue ? '是' : '否'
                }else if(cellValue == null){
                    return this.defaultCellValue
                }
                return cellValue
            },
            // 表格单选
            handleCurrentChange(val) {
                this.currentRow = val
            },
            // 表格多选
            handleSelectionChange(val) {
                this.multipleSelection = val
            },
            // 工具栏刷新按钮点击事件
            toolbarRefreshClick(){
                // 刷新默认加载当前页数据，如果有分页的话，如果没有分页只是多个分页参数，也不影响
                this.handlePageChange()
            },
            // 按钮的标签
            operationButtonLabel(button){
                if(typeof button.label == 'function'){
                    return button.label(this.currentRow)
                }
                if(button.disabled_label !== undefined){
                    if(this.isButtonDisabled(button)){
                        return button.disabled_label
                    }
                }
                return button.label
            },
            // 按钮是否禁用
            isButtonDisabled(button){
                if(button.disabled === true){
                    return true
                }else if(button.disabledOnMissingSelect == true){
                    if(!this.currentRow){
                        return true
                    }else if(typeof button.disabled == 'function'){
                        return button.disabled(this.currentRow)
                    }
                }else if(typeof button.disabled == 'function'){
                    return button.disabled(this.currentRow)
                }
                return false
            },
            // 表格工具按钮的点击事件
            handleOperations(button){
                let action = button.action
                if(typeof action == 'function'){
                    action(this.currentRow)
                    return
                }

                let url = button.url
                if(typeof url == 'function'){
                    url = button.url(this.currentRow)
                }
                if(url){
                    let prop = getPathVar(url)
                    if(this.currentRow){
                        url = putPathVar(url,prop,this.currentRow[prop])
                    }
                }

                switch (action) {
                    case 'nav':{
                        // 可以在路由上添加参数
                        if(button.routeQuery){

                            let query = {}
                            if (typeof button.routeQuery == 'string') {
                                if(this.currentRow){
                                    query[button.routeQuery] = this.currentRow[button.routeQuery]
                                }

                            }else if (typeof button.routeQuery == 'function') {
                                query = button.routeQuery(this.currentRow)
                            }else if (isArray(button.routeQuery)) {
                                if(this.currentRow){
                                    button.routeQuery.forEach(item=>{
                                        query[item] = this.currentRow[item]
                                    })
                                }
                            }else if (this.$_object_isObject(button.routeQuery)) {
                                query = button.routeQuery
                            }
                            this.$router.push({
                                path: url,
                                query:query
                            })
                        }else {
                            this.$router.push(url)
                        }
                        break
                    }
                    case 'delete':{
                        this.doDelete(url,button)
                        break
                    }
                    case 'enableOrDisable':{
                        this.enableOrDisable(url,button)
                        break
                    }
                    case 'detail':{
                        this.$refs.formDetailDialog.show()
                        break
                    }
                    case 'exportTableExcel':{
                        break
                    }
                    case 'exportTableCsv':{
                        break
                    }
                }
            },
            // 获取表格数据选中条的标签，以用作确认提示
            getUniqueLabel(){
              let r = ''
              if(typeof this.uniqueLabel == 'string'){
                  r = this.uniqueLabel
                  if(this.currentRow){
                      r = this.currentRow[this.uniqueLabel]
                  }
              }  else if(typeof this.uniqueLabel == 'function'){
                  r = typeof this.uniqueLabel(this.currentRow)
              }
              return r || ''
            },
            // 删除
            doDelete(url,button){
                let selfTip = '确定要删除'+ this.getUniqueLabel() +'吗, 是否继续?'
                if(button.delete && button.delete.tip){
                    if(typeof button.delete.tip == 'function'){
                        selfTip = button.delete.tip(this.currentRow)
                    }else {
                        selfTip = button.delete.tip.replace('${}')
                    }
                }

                this.$confirm(selfTip, '提示', {
                    type: 'warning'
                }).then(() => {
                    this.$set(this.localButtonLoading,button.code,true)
                    this.axios.delete(url)
                        .then(res => {
                            this.$message.success('删除成功')
                            // 重新加载数据
                            this.refreshData()
                        })
                        .catch(error => {
                            if(error.response){
                                if(error.response.status == 404){
                                    this.$message.error('数据不存在，请刷新数据再试')
                                }else {
                                    this.$message.error(error.response.data.msg)
                                }
                            }else {
                                this.$message.error('网络错误或服务不可用')
                            }
                        }).finally(()=>{
                        this.$set(this.localButtonLoading,button.code,false)
                    })
                })
            },
            // 内置禁用启用
            enableOrDisable(url,button){
                if(!this.currentRow){
                    this.$message.error('请先选中一条数据')
                    return
                }
                let prop = 'isDisabled'
                let reasonProp = 'disabledReason'

                if(button.enableOrDisable){
                    prop = button.enableOrDisable.prop
                    reasonProp = button.enableOrDisable.reasonProp
                }
                let prompt = '请输入'+ (this.currentRow[prop] ? '启用': '禁用') +'原因'
                if(button.prompt){
                    if(typeof button.prompt == 'function'){
                        prompt = button.prompt(this.currentRow)
                    }else{
                        prompt = button.prompt
                    }
                }
                this.$prompt(prompt, '提示', {
                    inputErrorMessage: '原因不能为空',
                    inputValidator:(value)=>{return !!value}
                }).then(({ value }) => {
                    let data = {
                        version: this.currentRow.version
                    }
                    data[prop] = !this.currentRow[prop]
                    data[reasonProp] = value
                    this.$set(this.localButtonLoading,button.code,true)
                    this.axios.patch(url,data)
                        .then(res => {
                            this.$message.success('操作成功')
                            // 重新加载数据
                            this.toolbarRefreshClick()
                        })
                        .catch(error => {
                            if(error.response){
                                if(error.response.status == 404){
                                    this.$message.error('数据不存在，请刷新数据再试')
                                }else {
                                    this.$message.error(error.response.data.msg)
                                }
                            }else {
                                this.$message.error('网络错误或服务不可用')
                            }
                        }).finally(()=>{
                        this.$set(this.localButtonLoading,button.code,false)
                    })
                })
            },
            // 工具按钮，列显示，默认全部显示
            toolbarMoreCheckAll(){
                let r = []
                this.columns.forEach(item =>{
                    r.push(item.prop)
                })
                this.toolbarMore.checkedItems = r
            },
            // 多选，获取选中的行
            getCheckedRows(){
                return this.multipleSelection
            },
            // 获取未选中行数据，多选情况下使用
            getUncheckedRows(){
                let checkedKeys = this.getCheckedKeys()
                return this.tableData.filter(item => checkedKeys.indexOf(item[this.keyProp]) < 0)
            },
            // 多选，获取选中的key
            getCheckedKeys(){
                return this.multipleSelection.map(item => item[this.keyProp])
            },
            // 多选，获取未选中的key
            getUncheckedKeys(){
                let checkedKeys = this.getCheckedKeys()
               return this.tableData.filter(item => checkedKeys.indexOf(item[this.keyProp])< 0).map(item => item[this.keyProp])
            },
            // 取消选择,同时支持多选和单选
            clearSelection(){
                this.$refs.table.clearSelection()
                this.$refs.table.setCurrentRow()
            },
            // 设置按钮的加载状态，code为button中指定的code值，如果未指定则是默认的code+index索引字符串value=true或false
            // 也可以通过buttonLoading方式改变状态
            setOperationButtonLoading(code,value){
                this.$set(this.localButtonLoading,code,value)
            },
            // 加载多选选中的值
            getCheckedData(){
                if(!this.checkedKeysUrl) return
                this.axios.get(this.checkedKeysUrl)
                    .then((res) => {
                        this.localCheckedKeys = res.data
                    }).catch(error=>{
                    if(error.response){
                        if(error.response.status == 401){
                            return
                        }
                        if(error.response.status != 404){
                            this.$message.error(error.response.data.msg)
                        }
                    }else{

                        this.$message.error('网络错误或服务不可用')
                    }
                    this.localCheckedKeys = []
                })
            },
            // 表格数据行中使用的方便，格式化数据，目前只格式化时间，
            formatDatetime( scope,column){
                let format = 'yyyy-MM-dd'
                let value = this.$_object_getValue(scope.row,column.prop)
                if(value){
                    switch (column.formatType) {
                        case 'date':{
                            return formatDate(parseDate(value,format),format)
                        }
                        case 'datetime':{
                            format += ' HH:mm:ss'
                            return formatDate(parseDate(value,format),format)
                        }
                    }
                }

                return this.defaultCellValue
            }
        },
        watch:{
            loading(val){
                this.localLoading = val
            },
            data(val){
                this.localData = val
                this.init(this.localData,this.queryParams)
            },
            tableData(val){
                this.setChecked(this.localCheckedKeys)
            },
            localCheckedKeys(val){
                this.setChecked(val)
            },
            checkedKeys(val){
                this.localCheckedKeys = val
            },
            queryParams(val){
                this.init(this.data,val)
            },
            // 改变操作按钮的loading状态，也可以单个调用方法指定setOperationButtonLoading
            buttonLoading(val){
                for(let prop in val){
                    if(this.localButtonLoading[prop] == undefined){
                        this.$set(this.localButtonLoading,prop,val[prop])
                    }else  if(this.localButtonLoading[prop] != val[prop]){
                        this.$set(this.localButtonLoading,prop,val[prop])
                    }
                }
                this.localButtonLoading = val
            }
        }
    }
</script>

<style scoped>
    /* 表行中显示图片缩略样式 */
    .table-wrapper .image-thumbnail{
        border: 1px solid #d7dae2;
        width: 25px;
        height:25px;
        cursor: pointer;
        border: none;
    }
</style>
